﻿#include "asm-generic/gpio.h"
#include "asm/uaccess.h"
#include "linux/jiffies.h"
#include "linux/types.h"
#include "linux/wait.h"
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/delay.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>


#define DRV_FILE "DHT11"

struct gpio_desc{
	int gpio;
	int irq;
    char *name;
    int key;
	struct timer_list key_timer;
} ;

static struct gpio_desc gpios[1] = {
    {115, 0, "harry_dht11", },
};

/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_class;
static u64 g_dht11_irq_time[84];
static int g_dht11_irq_cnt = 0;


/* 环形缓冲区 */
#define BUF_LEN 128
static char g_keys[BUF_LEN];
static int r, w;

struct fasync_struct *button_fasync;

#define NEXT_POS(x) ((x+1) % BUF_LEN)

static int is_key_buf_empty(void)
{
	return (r == w);
}

static int is_key_buf_full(void)
{
	return (r == NEXT_POS(w));
}

static void put_key(char key)
{
	if (!is_key_buf_full())
	{
		g_keys[w] = key;
		w = NEXT_POS(w);
	}
}

static char get_key(void)
{
	char key = 0;
	if (!is_key_buf_empty())
	{
		key = g_keys[r];
		r = NEXT_POS(r);
	}
	return key;
}


static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);

// static void key_timer_expire(struct timer_list *t)

void parse_dht11_data(void)
{
	/*parsing data: the pulse low or high depend on irq time*/
	int i;
	u64 high_time;
	unsigned char data = 0;
	unsigned char datas[5];
	int byte = 0;
	int bits_get = 0;
	int crc;
	if (g_dht11_irq_cnt<81)
	{
		put_key(-1);
		put_key(-1);
		g_dht11_irq_cnt = 0;
		free_irq(gpios[0].irq, &gpios[0]);
		wake_up_interruptible(&gpio_wait);
		return;
	}
	
	for (i = g_dht11_irq_cnt-80; i < g_dht11_irq_cnt; i+=2)
	{
		high_time = g_dht11_irq_time[i] - g_dht11_irq_time[i-1];
		data <<= 1;
		if (high_time>40000)
		{
			/* high pulse */
			data |= 1;
		}
		bits_get++;
		if (bits_get == 8)
		{
			datas[byte] = data;
			byte++;
			data = 0;
			bits_get = 0;
		}
	}
	
	/* put data into circle buffer data*/
	crc = datas[0]+datas[1]+datas[2]+datas[3];
	if (crc == datas[4])
	{
		put_key(datas[0]);
		put_key(datas[2]);
	}
	else
	{
		put_key(-1);
		put_key(-1);
	}
	/*wake up the gpio_wait data*/
	g_dht11_irq_cnt = 0;
	free_irq(gpios[0].irq, &gpios[0]);
	wake_up_interruptible(&gpio_wait);
}
static void key_timer_expire(unsigned long data)
{
	gpio_request(gpios[0].gpio, gpios[0].name);
	gpio_direction_output(gpios[0].gpio, 1);
	gpio_free(gpios[0].gpio);
	/* parse data*/
	parse_dht11_data();

}

static irqreturn_t dht11_isr(int irq, void *dev_id)
{
	struct gpio_desc *gpio_desc = dev_id;
	/* revord the irq time*/
	g_dht11_irq_time[g_dht11_irq_cnt]=ktime_get_ns();
	/* accumulated irq count*/
	g_dht11_irq_cnt++;
	/*if the count is enough */
	if (g_dht11_irq_cnt == 84)
	{
		del_timer(&gpio_desc->key_timer);
		gpio_request(gpios[0].gpio, gpios[0].name);
		gpio_direction_output(gpios[0].gpio, 1);
		gpio_free(gpios[0].gpio);
		parse_dht11_data();
	}
	else
	{
		mod_timer(&gpios[0].key_timer, jiffies + 10);
	}
	
	
	return IRQ_HANDLED;
}

/* */
static ssize_t dht11_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int err;
	/* send 18ms low pulse*/
	char kern_buf[2];
	if (size != 2)
		return -EINVAL;

	/*init timer*/
	setup_timer(&gpios[0].key_timer, key_timer_expire, (unsigned long)&gpios[0]);
	//timer_setup(&gpios[i].key_timer, key_timer_expire, 0);
	gpios[0].key_timer.expires = ~0;
	add_timer(&gpios[0].key_timer);
	printk("doing read\n");
	/*init bus line*/
	err = gpio_request(gpios[0].gpio, gpios[0].name);
	gpio_direction_output(gpios[0].gpio, 0);
	mdelay(18);
	gpio_direction_input(gpios[0].gpio);
	mdelay(20);
	gpio_free(gpios[0].gpio);
	/* request irq */
	gpios[0].irq  = gpio_to_irq(gpios[0].gpio);

	err = request_irq(gpios[0].irq, dht11_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[0].name, &gpios[0]);
	/*sleep and wait event */
	wait_event_interruptible(gpio_wait, !is_key_buf_empty());



	/* copy_to_user */
	kern_buf[0] = get_key();
	kern_buf[1] = get_key();
	if (kern_buf[0]==(char)-1 && kern_buf[1]==(char)-1)
		return -EIO;
	err = copy_to_user(buf, kern_buf, 2);/* copy 2 bytes*/
	return 2;
}
/* 定义自己的file_operations结构体                                              */
static struct file_operations gpio_key_drv = {
	.owner	 = THIS_MODULE,
	.read    = dht11_read,
};

/* 入口函数 */
static int __init dht11_init(void)
{
    
	printk("%s %s line %d\n",DRV_FILE, __FUNCTION__, __LINE__);

	/* 注册file_operations 	*/
	major = register_chrdev(0, "harry_dht11", &gpio_key_drv);  /* /dev/gpio_desc */

	gpio_class = class_create(THIS_MODULE, "harry_dht11_class");
	if (IS_ERR(gpio_class)) {
		printk("%s %s line %d\n", DRV_FILE, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "harry_dht11");
		return PTR_ERR(gpio_class);
	}

	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "harry_dht11"); /* /dev/dht11 */
	return 0;
}

/* 有入口函数就应该有出口函数：卸载驱动程序时，就会去调用这个出口函数
 */
static void __exit dht11_exit(void)
{
    
	printk("%s %s line %d\n", DRV_FILE, __FUNCTION__, __LINE__);

	device_destroy(gpio_class, MKDEV(major, 0));
	class_destroy(gpio_class);
	unregister_chrdev(major, "harry_dht11");
}


/* 7. 其他完善：提供设备信息，自动创建设备节点                                     */

module_init(dht11_init);
module_exit(dht11_exit);

MODULE_LICENSE("GPL");


